﻿using System.ComponentModel.DataAnnotations.Schema;
using System.Reflection;
using EasyDDD.Domain;

namespace EasyDDD.Application
{
    public abstract class AutoMapperProfile : Profile
    {
        public AutoMapperProfile()
        {
            this.CreateMap<DateTimeOffset, DateTime>();
            this.CreateMap<DateTime, DateTimeOffset>();
            ApplicationAutoMapperProfile(Assembly.GetCallingAssembly());
        }

        public AutoMapperProfile(Assembly domainAssembly)
        {
            DomainAutoMapperProfile(domainAssembly);
            ApplicationAutoMapperProfile(Assembly.GetCallingAssembly());
        }

 
        private void DomainAutoMapperProfile(Assembly domainAssembly)
        {
            var appTypes = domainAssembly.GetExportedTypes();

            foreach (Type item in appTypes)
            {
                if (typeof(Key<int>).IsAssignableFrom(item))
                {
                    this.CreateMap(item, typeof(int)).ConvertUsing(e => ((Key<int>)e).Value);
                }
                if (typeof(Key<long>).IsAssignableFrom(item))
                {
                    this.CreateMap(item, typeof(long)).ConvertUsing(e => ((Key<long>)e).Value);
                }
                if (typeof(Key<string>).IsAssignableFrom(item))
                {
                    this.CreateMap(item, typeof(string)).ConvertUsing(e => ((Key<string>)e).Value);
                }
                if (typeof(Key<Guid>).IsAssignableFrom(item))
                {
                    this.CreateMap(item, typeof(Guid)).ConvertUsing(e => ((Key<Guid>)e).Value);
                }
            }
        }
        private void ApplicationAutoMapperProfile(Assembly appAssembly)
        {
            var appTypes = appAssembly.GetExportedTypes();
            foreach (Type item in appTypes)
            {
                if (item is null)
                {
                    continue;
                }

                var fromAttrs = item.GetCustomAttributes(typeof(AutoMapperFromAttribute));
                var toAttrs = item.GetCustomAttributes(typeof(AutoMapperToAttribute));

                foreach (AutoMapperFromAttribute fromAttr in fromAttrs)
                {
                    var mappingExpression = this.CreateMap(fromAttr.Type, item);
                    foreach (var p in item.GetProperties())
                    {
                        if (p.GetCustomAttributes().Any(e => e.GetType() == typeof(NotMappedAttribute)))
                        {
                            mappingExpression.ForMember(p.Name, opt => opt.Ignore());
                        }

                    }
                }

                foreach (AutoMapperToAttribute toAttr in toAttrs)
                {
                    var mappingExpression = this.CreateMap(item, toAttr.Type);
                    foreach (var p in item.GetProperties())
                    {
                        if (p.GetCustomAttributes().Any(e => e.GetType() == typeof(NotMappedAttribute)))
                        {
                            mappingExpression.ForMember(p.Name, opt => opt.Ignore());
                        }
                    }
                }
            }
        }
    }
}